/*********************************************************
          File Name:timer.cpp
          Author: Abby Cin
          Mail: abbytsing@gmail.com
          Created Time: Tue 29 Sep 2015 10:40:01 AM CST
**********************************************************/

#include "timer.h"
#include <sys/time.h>

Timer::Timer()
{
	struct tm *tv;
        time_t t = time(NULL);
        char m[5] ={0};         // current month
        char y[5] = {0};        // current year
        char dow[5] = {0};      // current day of week
        char dom[5] = {0};      // current day of month

        tv = localtime(&t);

        strftime(m, sizeof(m), "%m", tv);       // 01~12
        strftime(y, sizeof(y), "%y", tv);       // 0~99
        strftime(dow, sizeof(dow), "%w", tv);   // 0~6
        strftime(dom, sizeof(dom), "%d", tv);   // 01~31

        month = std::string(m);
        year = std::string(y);
        day_of_week = std::string(dow);
        day_of_month = std::string(dom);
	
/*
        month = std::stod(m);
        year = std::stod(y);
        day_of_week = std::stod(dow);
        day_of_month = std::stod(dom);
*/
}
                
Timer::Timer(int h, int m, int s, int ms) :  Timer() 
{ 
	hour = h;
	min = m;
	sec = s;
	msec = ms;
}

Timer &Timer::operator=(Timer &a)
{
        hour = a.hour;
        min = a.min;
        sec = a.sec;
        msec = a.msec;

        return *this;
}

Timer &Timer::operator+(int s)
{
        sec += s;
        refresh();
        return *this;
}

bool Timer::operator>(Timer &t)
{
        return (this->to_sec() > t.to_sec());
}

bool Timer::operator<(Timer &t)
{
        return (this->to_sec() < t.to_sec());
}

void Timer::set_time(std::string ts)
{
        hour = std::stod(ts.substr(0, 2));
	std::string tmp = ts.substr(3, 2);
        min = std::stod(tmp == "00" ? "0" : tmp);
	tmp = ts.substr(6, 2);
        sec = std::stod(tmp == "00" ? "0" : tmp);
        msec = 0;
}

long Timer::to_sec()
{
        return (hour * 3600 + min * 60 + sec);
}

void Timer::add(int s)
{
        sec += s;
        refresh();             // diff to original
}

bool Timer::is_between(Timer &t1, Timer &t2)
{
        long t1_sec, t2_sec, this_sec;

        t1_sec = t1.to_sec();
        t2_sec = t2.to_sec();
        this_sec = this->to_sec();

        if(t1_sec > t2_sec)
        {
                if(t1_sec > this_sec && this_sec > t2_sec)
                        return true;
                else
                        return false;
        }
        else
        {
                if(t1_sec < this_sec && this_sec < t2_sec)
                        return true;
                else
                        return false;
        }
        
        return false;
}

Timer &Timer::update()
{
        struct  tm *tv;
        struct timeval tval;
        time_t tmp = time(NULL);
        
        tv = localtime(&tmp);

        gettimeofday(&tval, NULL);      // may be lag off

        hour = tv->tm_hour;
        min = tv->tm_min;
        sec = tv->tm_sec;
        msec = tval.tv_usec / 1000;
	
	return *this;
}

Timer &Timer::update(int h, int m, int s, int ms)
{
        hour = h; 
        min = m;
        sec = s;
        msec = (ms == 0) ? 0 : ms;
	
	return *this;
}

long Timer::interval(Timer &t)
{
        if(*this > t)					// call overload method
                return this->to_sec() - t.to_sec();
        else
                return t.to_sec() - this->to_sec();
}

std::string Timer::get_time(bool full)
{
        std::stringstream is;

        is << format(hour) << ":" << format(min) << ":" << format(sec);

        if(full)
                is << ":" << format(msec, 4);

        return is.str();
}

bool Timer::is_leap_year(int year)
{
        if((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
                return true;
        else
                return false;
}

// arguments: 2015 10 1 5; means return the date of first friday in Oct in 2015  
int Timer::find_date_by_wday(int year, int month, int wday_index, int wday)
{
        bool leap_year = is_leap_year(year);
        struct tm t;
        struct tm *out;

	t.tm_year = year - 1900;
	t.tm_mon = month - 1;	// 0~11
        t.tm_hour = 8;
        t.tm_min = 0;
        t.tm_sec = 0;
        t.tm_mday = 1;


        time_t tmp = mktime(&t);

        out = localtime(&tmp);

        int first_day_of_month = 1;
        int eta_to_wday = out->tm_wday != wday ? wday - out->tm_wday : 0;

        // first friday
        int first_wday = first_day_of_month + eta_to_wday;
	int offset = wday_index > 1 ? (wday_index - 1) * 7 : 0;
        int res = first_wday + offset;
	
	if(month < 8)
	{
		if(month % 2 == 0)
		{
			if(month == 2 && leap_year)
				res = res > 29 ? -1 : res;
			else if(month == 2 && !leap_year)
				res = res > 28 ? -1 : res;
			else
				res = res > 30 ? -1 : res;
		}
		else
			res = res > 31 ? -1 : res;
	}
	else if(month >= 8)
	{
		if(month % 2 == 0)
			res = res > 31 ? -1 : res;
		else
			res = res > 30 ? -1 : res;
	}
				
        return res;
}
